<!--
 * @Description: 
 * @Autor: zhangbing
 * @Date: 2019-11-22 00:18:46
 * @LastEditors: zhangbing
 * @LastEditTime: 2021-08-16 19:21:07
-->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <!--  真实的DOM转化成虚拟DOM -->
  <div id="root">
    <div class="c1">
      <div title="tt1" id="id">hello1</div>
      <div title="tt2">hello2</div>
      <div title="tt3">hello3</div>
      <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
      </ul>
    </div>
  </div>

  <script>

    /* 
        怎么将虚拟DOM转化为真实的DOM
        怎么将真是的dom转化为虚拟DOM
     */

    // 为什么要使用虚拟 DOM? 性能
    // <div /> => { tag: 'div' }
    // 文本节点 => { tag: undefined, value: '文本节点' }
    // <div title="1" class="c" /> => { tag: 'div', data: { title: '1', class: 'c' } }
    // <div><div /></div> => { tag: 'div', children: [ { tag: 'div' } ] }

    class VNode {
      constructor(tag, data, value, type) {
        this.tag = tag && tag.toLowerCase(); // 描述标签名
        this.data = data; // 描述属性
        this.value = value; // 描述文本节点
        this.type = type; // 描述节点类型
        this.children = []; // 描述子节点
      }

      appendChild(vnode) {
        this.children.push(vnode);
      }
    }

    /** 
     * 使用递归 来遍历 DOM 元素, 生成 虚拟 DOM
     * Vue 中的源码使用的 栈结构 , 使用栈存储 父元素来实现递归生成
     */
    function getVNode(node) {
      let nodeType = node.nodeType;
      let _vnode = null; // 用来表示虚拟DOM的变量
      if (nodeType === 1) {
        // 元素
        let nodeName = node.nodeName;
        let attrs = node.attributes; // 这里是一个伪数组
        let _attrObj = {}; // 表示属性的对象
        for (let i = 0; i < attrs.length; i++) { // attrs[ i ] 属性节点 ( nodeType == 2 )
          _attrObj[attrs[i].nodeName] = attrs[i].nodeValue;
        }
        _vnode = new VNode(nodeName, _attrObj, undefined, nodeType);

        // 考虑 node 的子元素
        let childNodes = node.childNodes;
        for (let i = 0; i < childNodes.length; i++) {
          _vnode.appendChild(getVNode(childNodes[i])); // 递归
        }

      } else if (nodeType === 3) {

        _vnode = new VNode(undefined, undefined, node.nodeValue, nodeType);
      }

      return _vnode;
    }


    let root = document.querySelector('#root');

    let vroot = getVNode(root);

    console.log(vroot);
    /* 
      VNode {tag: "div", data: {…}, value: undefined, type: 1, children: Array(3)}
      children: (3) [VNode, VNode, VNode]
      data: {id: "root"}
      tag: "div"
      type: 1
      value: undefined
      [[Prototype]]: Object
    
    */

    // 将 vNode 转换为真正的 DOM ( 作业 )
    function parseVNode(vnode) {

    }

  </script>
</body>

</html>